# Copyright (C) 2007 Insecure.Com LLC.
#
# Authors: Guilherme Polo <ggpolo@gmail.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 
# USA

import gtk
import gobject
import pango
import time
from gettext import gettext as _
import tl # timeline


view_by_zoom = [_("Year"), _("Month"), _("Day"), _("Hour")]


class HIGFrame(gtk.Frame):
    """
    Frame without border with bold label.
    """
    def __init__(self, label=None):
        gtk.Frame.__init__(self)
        
        self.set_shadow_type(gtk.SHADOW_NONE)
        self._flabel = gtk.Label()
        self._set_label(label)
        self.set_label_widget(self._flabel)

    def _set_label(self, label):
        self._flabel.set_markup("<b>%s</b>" % label)


class yah_window(gtk.Window):
    def __init__(self, tldaddy):
        gtk.Window.__init__(self)
        
        self.set_title(_("You are here!"))
        self.youarehere = tl.youarehere(tldaddy) 
        self.add(self.youarehere)


class mainwin(gtk.Window):
    def __init__(self):
        gtk.Window.__init__(self)
        
        self.connect('delete-event', self.on_quit)
        self.set_title(_("TimeLine 0.2"))
        
        # timeline 
        cur_year = int(time.strftime('%Y'))
        self.tl = tl.main(start_year=cur_year,
                          start_month=int(time.strftime('%m')), 
                          start_day=int(time.strftime('%d')),
                          start_hour=int(time.strftime('%H')),
                          testing_mode=False,
                          zoom=3, # view by hour
                          # Defaults follows, just for demonstration
                          year_range=(1970, 3000), # year range
                          show_every_date=False, # show only higlighted dates
                          border_on_focus=True, # draw border on focus
                          fixed_height=True, # cells with fixed height
                          draw_back_shadow=True, # draw shadow
                          light_on_hover=True, # draw light on hover
                          )
        
        self.larrow = tl.arrow(-1, self.tl) # left arrow (previous date)
        self.rarrow = tl.arrow(1, self.tl) # right arrow (next date)
        
        self.downarrow = tl.arrow(-2, self.tl) # down arrow (zoom in)
        self.uparrow = tl.arrow(-3, self.tl) # up arrow (zoom out)
        self.tlegend = tl.legend(self.tl) # legend
        
        self.youarehere = tl.youarehere(self.tl)
        # --
        
        # tooltips
        self.tooltips = gtk.Tooltips()
        self.tooltips.set_tip(self.uparrow, _("Zoom out one level."))
        self.tooltips.set_tip(self.downarrow, _("Zoom in one level."))
        self.tooltips.set_tip(self.larrow, _("Go to the previous date."))
        self.tooltips.set_tip(self.rarrow, _("Go to the next date."))
        
        # statusbar
        self.statusbar = gtk.Statusbar()
        self.sbcid = self.statusbar.get_context_id("TimeLine")
        
        
        self.tltitle = gtk.Label() # timeline title label
        self.tlegendtitle = gtk.Label()
        self.tlegendtitle.set_markup(_("<b>Legend</b>")) # legend label
        
        # info frame
        self.infoframe = HIGFrame(_("TimeLine"))
        self.zoom_level_l = gtk.Label(_("Zoom Level:"))
        self.zoom_level = gtk.Label()
        self.viewing_by_l = gtk.Label(_("Viewing by:"))
        self.viewing_by = gtk.Label()
        self.cur_date_l = gtk.Label(_("Current date set:"))
        self.cur_date = gtk.Label()
        self.testing_l = gtk.Label(_("Testing mode:"))
        self.testing = gtk.Label(_(self.tl.testing and "On" or "Off"))
        self.fixed_l = gtk.Label(_("Fixed cell height:"))
        self.fixed = gtk.Label(_(self.tl.fixed_height and "Yes" or "No"))
        
        # options frame
        self.optframe = HIGFrame(_("Options"))
        self.show_edate = gtk.CheckButton(_("Show every date on TimeLine"))
        self.show_edate.set_active(self.tl.show_every_date)
        self.show_edate.connect('toggled', self.change_edate)
        self.evtpop = gtk.CheckButton(_("On click popup window"))
        self.evtpop.set_active(self.tl.evt_popup)
        self.evtpop.connect('toggled', self.change_popup)
        self.bshadow = gtk.CheckButton(_("Shadowed cells"))
        self.bshadow.set_active(self.tl.draw_backshadow)
        self.bshadow.connect('toggled', self.change_bshadow)
        self.hlight = gtk.CheckButton(_("Light on cell hover"))
        self.hlight.set_active(self.tl.light_on_hover)
        self.hlight.connect('toggled', self.change_hlight)
        self.cbdraw = gtk.CheckButton(_("Draw cell border"))
        self.cbdraw.set_active(self.tl.cell_border)
        self.cbdraw.connect('toggled', self.change_cbhover)
        self.bdraw = gtk.CheckButton(_("Border on widget focus"))
        self.bdraw.set_active(self.tl.draw_border)
        self.bdraw.connect('toggled', self.change_bfocus)
        self.min_font_l = gtk.Label(_("Minimal font size: "))
        adj = gtk.Adjustment(self.tl.min_font_size, 8, 54, 1.0, 2.0, 0.0)
        self.min_font = gtk.SpinButton(adj, 0, 0)
        adj.connect("value_changed", self.c_min_font)
        self.year_start = gtk.Label(_("Year range, start:"))
        adj = gtk.Adjustment(self.tl.year_range[0], self.tl.year_range[0],
                             self.tl.year_range[1], 1.0, 10.0, 0.0)
        self.year_start_sb = gtk.SpinButton(adj, 0, 0)
        adj.connect("value_changed", self.v_year_start)
        self.year_end = gtk.Label(_("end:"))
        adj = gtk.Adjustment(self.tl.year_range[1], self.tl.year_range[0], 
                             self.tl.year_range[1], 1.0, 10.0, 0.0)
        self.year_end_sb = gtk.SpinButton(adj, 0, 0)
        adj.connect("value_changed", self.v_year_end)
        self.year_start_sb.set_numeric(True)
        self.year_end_sb.set_numeric(True)
        self.invalid_l = gtk.Label(_("Invalid range"))
        self.invalid_l.set_sensitive(False)
        
        #gobject.timeout_add(5, self.change_date) # heavy date tests
        #gobject.timeout_add(5, self.zoom)        # heavy date tests
        
        self.date_changed(None)
        self._conn_evts()
        self._create_ui()
        self._layout()

    
    def attach_to(self, table, widget, x0, y0, x1, y1, options):
        """
        Attaches a widget left aligned in a gtk.Table
        """
        align = gtk.Alignment(0, 0, 0, 0)
        align.add(widget)
        table.attach(align, x0, y0, x1, y1, options)

    
    def write_tip(self, event):
        """
        Write tip if user clicked on up/down arrow to change zoom level.
        """
        self.statusbar.pop(self.sbcid)
        self.statusbar.push(self.sbcid, "Tip: You may use the mouse scroll \
wheel when hovering the TimeLine to change zoom level.")
    
    
    def scroll_event(self, widget, event):
        """
        Handles mouse wheel scroll to zoom in/out.
        """
        self.statusbar.push(self.sbcid, "")
        
        if event.direction == gtk.gdk.SCROLL_DOWN:
            if not self.downarrow.state:
                self.tl.zoom_in()
        else:
            if not self.uparrow.state:
                self.tl.zoom_out()
    

    def c_min_font(self, event):
        self.tl.min_font_size = self.min_font.get_value_as_int()
        self.tl.emit('font-change-notify')


    def v_year_start(self, event):
        start = self.year_start_sb.get_value_as_int()
        end = self.year_end_sb.get_value_as_int()
        if (start >= end - 1):
            self.invalid_l.set_sensitive(True)
        else:
            self.invalid_l.set_sensitive(False)
            # set new range
            self.tl.year_range = (start, end)
            self.tl.emit('range-change-notify')

    def v_year_end(self, event):
        start = self.year_start_sb.get_value_as_int()
        end = self.year_end_sb.get_value_as_int()
        if (start >= end - 1):
            self.invalid_l.set_sensitive(True)
        else:
            self.invalid_l.set_sensitive(False)
            # set new range
            self.tl.year_range = (start, end)
            self.tl.emit('range-change-notify')
    
    
    def change_edate(self, event):
        self.tl.show_every_date = (not self.tl.show_every_date)
        self.tl.queue_draw()
    
    
    def change_bfocus(self, event):
        self.tl.draw_border = (not self.tl.draw_border)
        self.tl.queue_draw()
    
    
    def change_popup(self, event):
        self.tl.evt_popup = (not self.tl.evt_popup)


    def change_hlight(self, event):
        self.tl.light_on_hover = (not self.tl.light_on_hover)
        self.tl.queue_draw()


    def change_cbhover(self, event):
        self.tl.cell_border = (not self.tl.cell_border)
        self.tl.queue_draw()
        

    def change_bshadow(self, event):
        self.tl.draw_backshadow = (not self.tl.draw_backshadow)
        self.tl.queue_draw()


    def date_changed(self, event):
        """
        Reconfigure demo.
        """
        if self.tl.can_zoom_in() and self.tl.can_zoom_out():
            self.uparrow.set_sensitive(True)
            self.downarrow.set_sensitive(True)
        elif self.tl.can_zoom_in():
            self.downarrow.set_sensitive(True)
            self.uparrow.set_sensitive(False)
        else:
            self.downarrow.set_sensitive(False)
            self.uparrow.set_sensitive(True)

        
        self.tltitle.set_markup("<span size='16500' weight='heavy'>%s \
</span>" % (self.tl.title_by_zoom()))
        
        self.cur_date.set_label("%s" % \
             '-'.join([str(c) for c in self.tl.get_date()]))
        self.zoom_level.set_label("%s" % str(self.tl.zoom))
        self.viewing_by.set_label("%s" % view_by_zoom[self.tl.zoom])

    def change_fwday(self, event):
        pass

    def change_hour(self, event):
        pass

    def change_day(self, event):
        pass

    def change_month(self, event):
        pass
    
    def change_year(self, event):
        pass     
    
    def mbtn_about(self, event):
        """
        About dialog.
        """
        dialog = gtk.MessageDialog(self,
                                   (gtk.DIALOG_MODAL |
                                    gtk.DIALOG_DESTROY_WITH_PARENT),
                                   gtk.MESSAGE_INFO, gtk.BUTTONS_OK,
                                   "A demo for testing TimeLine functionality \
(demo \n\is missing some functionality)\n\nAuthor: Guilherme Polo \
<ggpolo@gmail.com>")
        dialog.run()
        dialog.destroy()
    
    
    def on_quit(self, widget, event=None):
        gtk.main_quit()
    
    
    def _create_ui(self):
        """
        Create MenuBar for demo.
        """
        
        entries = (
            ( "FileMenu", None, "_File" ),              
            ( "PreferencesMenu", None, "_Edit" ),
            ( "HelpMenu", None, "_Help" ),
            
            # FileMenu     
            ( "Quit", gtk.STOCK_QUIT,                    
              "_Quit", "<control>Q",                    
              "Quit",                                    
                self.on_quit ),
            # HelpMenu
            ( "About", gtk.STOCK_ABOUT,                             
              "_About", None,                    
              "About",                                   
              self.mbtn_about), 
            # PreferencesMenu
            ( "Year", None,                              
              "Set _Year", None,                 
              "Set a Year for the Timeline",             
              self.change_year ),                    
            ( "Month", None,                            
              "Set _Month", None,              
              "Set a Month for the TimeLine",            
              self.change_month ),
            ( "Day", None,
              "Set _Day", None,
              "Set a Day for the TimeLine",
              self.change_day ),
            ( "Hour", None,
              "Set _Hour", None,
              "Set an Hour for the TimeLine",
              self.change_hour ),
            ( "FWDay", None,
              "Set first _Weekday", None,
              "Set the first weekday",
              self.change_fwday ),
        )
        
        
        ui_filemenu_info = """
        <menu action='FileMenu'>
            <menuitem action='Quit'/>
        </menu>"""
        
        ui_prefmenu_info = """
        <menu action='PreferencesMenu'>
              <menuitem action='Year'/>
             <menuitem action='Month'/>
             <menuitem action='Day'/>
            <menuitem action='Hour'/>
            <menuitem action='FWDay' />
        </menu>
        """
                     
        ui_helpmenu_ui = """
        <menu action='HelpMenu'>
            <menuitem action='About'/>
        </menu>
        """
        
        ui_info =  """
            <ui> 
                  <menubar name='Menubar'>
                    %s %s
                  </menubar>
            </ui>""" % (ui_filemenu_info, ui_helpmenu_ui)
        
        self.aactions = gtk.ActionGroup("Actions")
        self.aactions.add_actions(entries)
        
        self.ui = gtk.UIManager()
        self.ui.insert_action_group(self.aactions, 0)
        self.add_accel_group(self.ui.get_accel_group())
        self.ui.add_ui_from_string(ui_info) 
    
    
    def _exposed(self, widget, event):
        self.sw.set_size_request(650 + 4, int(self.tl.min_cell_height + 4) + 20)
    
    def _conn_evts(self):
        self.tl.connect('date-change-notify', self.date_changed)
        self.tl.connect('range-change-notify', self.date_changed)
        self.tl.connect('scroll_event', self.scroll_event)
        self.downarrow.connect('clicked', self.write_tip)
        self.uparrow.connect('clicked', self.write_tip)
        self.connect('expose-event', self._exposed)
    
    
    def _layout(self):
        main_vbox = gtk.VBox()
        main_vbox.set_border_width(0)
        
        vbox = gtk.VBox()
        vbox.set_border_width(6)
        
        main_vbox.pack_start(self.ui.get_widget("/Menubar"), False, False, 0)
        
        # up arrow, title, down arrow
        align = gtk.Alignment(0.5, 0.5, 0, 0)
        align.add(self.uparrow)
        vbox.pack_start(align, False, False, 3)
        align = gtk.Alignment(0.5, 0.5, 0, 0)
        align.add(self.tltitle)
        vbox.pack_start(align, False, False, 3)
        align = gtk.Alignment(0.5, 0.5, 0, 0)
        align.add(self.downarrow)
        vbox.pack_start(align, False, False, 6)
        
        # left arrow, timeline, right arrow
        tl_and_info_h = gtk.HBox()
        tl_and_info_h.set_border_width(6)
        tl_and_info = gtk.VBox()
        
        tlbox = gtk.HBox()
        align = gtk.Alignment(0, 1, 0, 0.5)
        align.add(self.larrow)
        tlbox.pack_start(align, False, False, 0)
        
        self.sw = gtk.ScrolledWindow()
        self.sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        align = gtk.Alignment(0, 1, 1, (self.tl.fixed_height) and 0.5 or 1)
        align.add(self.tl)
        self.sw.add_with_viewport(align)
        tlbox.pack_start(self.sw, True, True, 0)
        #tlbox.pack_start(align, True, True, 0)
        
        align = gtk.Alignment(0, 1, 0, 0.5)
        align.add(self.rarrow)
        tlbox.pack_end(align, False, False, 0)
        tl_and_info.pack_start(tlbox, not self.tl.fixed_height, 
                               not self.tl.fixed_height, 6)
        self.changeable = tl_and_info
        
        # info box        
        framebox = gtk.VBox()
        framebox.set_border_width(12)
        self.infoframe.add(framebox)
        
        t_rows = 5
        frame_t = gtk.Table(t_rows, 2, False)
        frame_t.set_row_spacings(6)
        frame_t.set_col_spacings(12)
        
        # attach widgets to table
        to_attach = ( self.cur_date_l, self.cur_date, self.zoom_level_l,
                                self.zoom_level, self.viewing_by_l, self.viewing_by,
                                self.testing_l, self.testing, self.fixed_l, self.fixed )
        
        for r in xrange(t_rows):
            self.attach_to(frame_t, to_attach[2*r], 0, 1, r, r+1, 
                                    gtk.FILL)
            self.attach_to(frame_t, to_attach[2*r+1], 1, 2, r, r+1,
                                    gtk.FILL|gtk.EXPAND)
        
        framebox.add(frame_t)
        tl_and_info.pack_start(self.infoframe, False, False, 6)
        tl_and_info_h.add(tl_and_info)
        
        # options box
        framebox = gtk.VBox()
        framebox.set_border_width(12)
        self.optframe.add(framebox)
        box1 = gtk.HBox()
        box1.pack_start(self.show_edate, False, False, 12)
        framebox.add(box1)
        box1 = gtk.HBox()
        box1.pack_start(self.bshadow, False, False, 12)
        framebox.add(box1)
        box1 = gtk.HBox()
        box1.pack_start(self.hlight, False, False, 12)
        framebox.add(box1)
        box1 = gtk.HBox()
        box1.pack_start(self.cbdraw, False, False, 12)
        framebox.add(box1)
        box1 = gtk.HBox()
        box1.pack_start(self.bdraw, False, False, 12)
        framebox.add(box1)
        # font size
        box1 = gtk.HBox()
        box1.pack_start(self.min_font_l, False, False, 12)
        box1.pack_start(self.min_font, False, False, 0)
        framebox.pack_start(box1, False, False, 6)
        # year range
        box1 = gtk.HBox()
        box1.pack_start(self.year_start, False, False, 12)
        box1.pack_start(self.year_start_sb, False, False, 0)
        box1.pack_start(self.year_end, False, False, 12)
        box1.pack_start(self.year_end_sb, False, False, 0)
        box1.pack_start(self.invalid_l, False, False, 12)
        framebox.add(box1)
                
        tl_and_info.pack_start(self.optframe, False, False, 0)
        
        # legend title, legend
        legendbox = gtk.VBox()
        legendbox.pack_start(self.tlegendtitle, False, False, 6)
        legendbox.pack_start(self.tlegend, False, False, 6)
        
        # paned to hold tl_and_info and legendbox
        pan = gtk.HPaned()
        pan.pack1(tl_and_info_h, resize=True)
        pan.add2(legendbox)
        
        vbox.pack_start(pan, True, True, 0)
        
        main_vbox.pack_start(vbox, True, True, 0)
        
        self.hb = gtk.HandleBox()
        self.hb.add(self.youarehere)
        main_vbox.add(self.hb)
        #self.hb.connect('child-detached', self.detc)
        
        main_vbox.pack_start(self.statusbar, False, False, 0)
        self.add(main_vbox)

    #def detc(self, widget, child):
    #    print dir(widget), dir(child)
   
    
    # "Tests"
    def change_date(self):
        self.tl.go_next_date()
        #self.tl.go_prev_date()
        print self.tl.title_by_zoom()
        return True
    
    
    def zoom(self):
        #self.tl.zoom_in()
        self.tl.zoom_out()
        print self.tl.get_zoom()
        return True
    
    
if __name__ == "__main__":
        win = mainwin()
        win.show_all()
        yah_win = yah_window(win.tl)
        yah_win.show_all()
        gtk.main()
